#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include "llist.h"
#include "h264tortp.h"

#define DEFAULT_DEST_PORT 1234
#define RTP_PAYLOAD_MAX_SIZE 1400
#define SEND_BUF_SIZE 1500
#define NAL_BUF_SIZE 1500 * 50
#define SSRC_NUM 10

uint16_t DEST_PORT;
linklist CLIENT_IP_LIST;
uint8_t SENDBUFFER[SEND_BUF_SIZE];
uint8_t nal_buf[NAL_BUF_SIZE];
uint8_t frame_buf[NAL_BUF_SIZE * 10];
uint8_t sps_buf[NAL_BUF_SIZE];
uint8_t sps_base64[NAL_BUF_SIZE * 2];
uint8_t pps_base64[NAL_BUF_SIZE * 2];
int rtpSocket;

static void add_client_list(linklist client_ip_list, char *ipaddr)
{
    struct sockaddr_in server_c;
    pnode pnode_tmp;
    const int on = 1;

    insert_nodulp_node(client_ip_list, ipaddr);
    pnode_tmp = search_node(CLIENT_IP_LIST, ipaddr);
    server_c.sin_family = AF_INET;
    server_c.sin_port = htons(DEST_PORT);
    server_c.sin_addr.s_addr = inet_addr(ipaddr);
    pnode_tmp->send_fail_n = 0;
    pnode_tmp->node_info.socket_c = socket(AF_INET, SOCK_DGRAM, 0);

    /*
     * 设置广播属性
     */
    if (setsockopt(pnode_tmp->node_info.socket_c, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
    {
        fprintf(stderr, "initSvr: Socket options set error.\n");
        exit(errno);
    }
    server_c.sin_family = AF_INET;
    server_c.sin_port = htons(DEST_PORT);
    server_c.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(pnode_tmp->node_info.socket_c, (struct sockaddr *)&server_c, sizeof(server_c)))
    {
        perror("bind");
    }

    return;
} /* static void add_client_list(linklist client_ip_list, char *ipaddr) */

static void send_data_to_client_list(uint8_t *send_buf, size_t len_sendbuf, RtpSession *server)
{
    int ret;

    // if ((ret = send(pnode_tmp0->node_info.socket_c, send_buf, len_sendbuf, MSG_DONTWAIT)) < 0) {
    if ((ret = send(server->serverSocket, send_buf, len_sendbuf, 0)) < 0)
    {
        fprintf(stderr, "----- send fail errno is %d----\n", errno);
        /* pnode_tmp->send_fail_n 失败次数加1 */
        if (errno > 0)
            server->send_fail_n++;

        /*
             * send连续失败次数达到阀值 MAX_SEND_FAIL_N 则删除该节点
             */
        // if (pnode_tmp0->send_fail_n > MAX_SEND_FAIL_N) {
        //     close(pnode_tmp0->node_info.socket_c);
        // pnode_tmp0 = delete_this_node(client_ip_list, pnode_tmp0);
        //   } /* if (pnode_tmp->send_fail_n > 20) */
        perror("send");
    } /* if (send(pnode_tmp0->node_info.socket_c, SENDBUF, send_bytes, 0) == -1) */

    return;
} /* void send_data_to_client_list(uint8_t *send_buf, size_t len_sendbuf, linklist client_ip_list) */

static int h264nal2rtp_send(int framerate, uint8_t *pstStream, int nalu_len, RtpSession *server)
{
    uint8_t *nalu_buf;
    nalu_buf = pstStream;
    // int nalu_len;   /* 不包括0x00000001起始码, 但包括nalu头部的长度 */
    rtp_header_t *rtp_hdr;
    nalu_header_t *nalu_hdr;
    fu_indicator_t *fu_ind;
    fu_header_t *fu_hdr;
    size_t len_sendbuf;

    int fu_pack_num;       /* nalu 需要分片发送时分割的个数 */
    int last_fu_pack_size; /* 最后一个分片的大小 */
    int fu_seq;            /* fu-A 序号 */

    server->ts_current += (90000 / framerate); /* 90000 / 25 = 3600 */

    /*
         * 加入长度判断，
         * 当 nalu_len == 0 时， 必须跳到下一轮循环
         * nalu_len == 0 时， 若不跳出会发生段错误!
         * fix by hmg
         */
    if (nalu_len < 1)
    {
        return -1;
    }

    if (nalu_len <= RTP_PAYLOAD_MAX_SIZE)
    {
        /*
             * single nal unit
             */

        memset(SENDBUFFER, 0, SEND_BUF_SIZE);

        /*
             * 1. 设置 rtp 头
             */
        rtp_hdr = (rtp_header_t *)SENDBUFFER;
        rtp_hdr->csrc_len = 0;
        rtp_hdr->extension = 0;
        rtp_hdr->padding = 0;
        rtp_hdr->version = 2;
        rtp_hdr->payload_type = H264;
        // rtp_hdr->marker = (pstStream->u32PackCount - 1 == i) ? 1 : 0;   /* 该包为一帧的结尾则置为1, 否则为0. rfc 1889 没有规定该位的用途 */
        rtp_hdr->seq_no = htons(++server->seq_num % UINT16_MAX);
        rtp_hdr->timestamp = htonl(server->ts_current);
        rtp_hdr->ssrc = htonl(server->ssrcNum);

        /*
             * 2. 设置rtp荷载 single nal unit 头
             */
#if 1
        nalu_hdr = (nalu_header_t *)&SENDBUFFER[12];
        nalu_hdr->f = (nalu_buf[0] & 0x80) >> 7;   /* bit0 */
        nalu_hdr->nri = (nalu_buf[0] & 0x60) >> 5; /* bit1~2 */
        nalu_hdr->type = (nalu_buf[0] & 0x1f);

#else
        SENDBUFFER[12] = ((nalu_buf[0] & 0x80))              /* bit0: f */
                         | (nalu_buf[0] & 0x60)              /* bit1~2: nri */
                         | (nalu_buf[0] & 0x1f);             /* bit3~7: type */
#endif

        /*
             * 3. 填充nal内容
             */

        memcpy(SENDBUFFER + 13, nalu_buf + 1, nalu_len - 1); /* 不拷贝nalu头 */

        /*
             * 4. 发送打包好的rtp到客户端
             */
        len_sendbuf = 12 + nalu_len;
        send_data_to_client_list(SENDBUFFER, len_sendbuf, server);
    }
    else
    { /* nalu_len > RTP_PAYLOAD_MAX_SIZE */
        /*
             * FU-A分割
             */

        /*
             * 1. 计算分割的个数
             *
             * 除最后一个分片外，
             * 每一个分片消耗 RTP_PAYLOAD_MAX_SIZE BYLE
             */
        fu_pack_num = nalu_len % RTP_PAYLOAD_MAX_SIZE ? (nalu_len / RTP_PAYLOAD_MAX_SIZE + 1) : nalu_len / RTP_PAYLOAD_MAX_SIZE;
        last_fu_pack_size = nalu_len % RTP_PAYLOAD_MAX_SIZE ? nalu_len % RTP_PAYLOAD_MAX_SIZE : RTP_PAYLOAD_MAX_SIZE;
        fu_seq = 0;

        for (fu_seq = 0; fu_seq < fu_pack_num; fu_seq++)
        {
            memset(SENDBUFFER, 0, SEND_BUF_SIZE);

            /*
                 * 根据FU-A的类型设置不同的rtp头和rtp荷载头
                 */
            if (fu_seq == 0)
            { /* 第一个FU-A */
                /*
                     * 1. 设置 rtp 头
                     */
                rtp_hdr = (rtp_header_t *)SENDBUFFER;
                rtp_hdr->csrc_len = 0;
                rtp_hdr->extension = 0;
                rtp_hdr->padding = 0;
                rtp_hdr->version = 2;
                rtp_hdr->payload_type = H264;
                rtp_hdr->marker = 0; /* 该包为一帧的结尾则置为1, 否则为0. rfc 1889 没有规定该位的用途 */
                rtp_hdr->seq_no = htons(++server->seq_num % UINT16_MAX);
                rtp_hdr->timestamp = htonl(server->ts_current);
                rtp_hdr->ssrc = htonl(server->ssrcNum);

                /*
                     * 2. 设置 rtp 荷载头部
                     */
#if 1
                fu_ind = (fu_indicator_t *)&SENDBUFFER[12];
                fu_ind->f = (nalu_buf[0] & 0x80) >> 7;
                fu_ind->nri = (nalu_buf[0] & 0x60) >> 5;
                fu_ind->type = 28;
#else /* 下面的错误以后再找 */
                SENDBUFFER[12] = (nalu_buf[0] & 0x80) >> 7   /* bit0: f */
                                 | (nalu_buf[0] & 0x60) >> 4 /* bit1~2: nri */
                                 | 28 << 3;                  /* bit3~7: type */
#endif

#if 1
                fu_hdr = (fu_header_t *)&SENDBUFFER[13];
                fu_hdr->s = 1;
                fu_hdr->e = 0;
                fu_hdr->r = 0;
                fu_hdr->type = nalu_buf[0] & 0x1f;
#else
                SENDBUFFER[13] = 1 | (nalu_buf[0] & 0x1f) << 3;
#endif

                /*
                     * 3. 填充nalu内容
                     */
                memcpy(SENDBUFFER + 14, nalu_buf + 1, RTP_PAYLOAD_MAX_SIZE - 1); /* 不拷贝nalu头 */

                /*
                     * 4. 发送打包好的rtp包到客户端
                     */
                len_sendbuf = 12 + 2 + (RTP_PAYLOAD_MAX_SIZE - 1); /* rtp头 + nalu头 + nalu内容 */
                send_data_to_client_list(SENDBUFFER, len_sendbuf, server);
            }
            else if (fu_seq < fu_pack_num - 1)
            { /* 中间的FU-A */
                /*
                     * 1. 设置 rtp 头
                     */
                rtp_hdr = (rtp_header_t *)SENDBUFFER;
                rtp_hdr->csrc_len = 0;
                rtp_hdr->extension = 0;
                rtp_hdr->padding = 0;
                rtp_hdr->version = 2;
                rtp_hdr->payload_type = H264;
                rtp_hdr->marker = 0; /* 该包为一帧的结尾则置为1, 否则为0. rfc 1889 没有规定该位的用途 */
                rtp_hdr->seq_no = htons(++server->seq_num % UINT16_MAX);
                rtp_hdr->timestamp = htonl(server->ts_current);
                rtp_hdr->ssrc = htonl(server->ssrcNum);

                /*
                     * 2. 设置 rtp 荷载头部
                     */
#if 1
                fu_ind = (fu_indicator_t *)&SENDBUFFER[12];
                fu_ind->f = (nalu_buf[0] & 0x80) >> 7;
                fu_ind->nri = (nalu_buf[0] & 0x60) >> 5;
                fu_ind->type = 28;

                fu_hdr = (fu_header_t *)&SENDBUFFER[13];
                fu_hdr->s = 0;
                fu_hdr->e = 0;
                fu_hdr->r = 0;
                fu_hdr->type = nalu_buf[0] & 0x1f;
#else /* 下面的错误以后要找 */
                SENDBUFFER[12] = (nalu_buf[0] & 0x80) >> 7   /* bit0: f */
                                 | (nalu_buf[0] & 0x60) >> 4 /* bit1~2: nri */
                                 | 28 << 3;                  /* bit3~7: type */

                SENDBUFFER[13] = 0 | (nalu_buf[0] & 0x1f) << 3;
#endif

                /*
                     * 3. 填充nalu内容
                     */
                memcpy(SENDBUFFER + 14, nalu_buf + RTP_PAYLOAD_MAX_SIZE * fu_seq, RTP_PAYLOAD_MAX_SIZE); /* 不拷贝nalu头 */

                /*
                     * 4. 发送打包好的rtp包到客户端
                     */
                len_sendbuf = 12 + 2 + RTP_PAYLOAD_MAX_SIZE;
                send_data_to_client_list(SENDBUFFER, len_sendbuf, server);
            }
            else
            { /* 最后一个FU-A */
                /*
                     * 1. 设置 rtp 头
                     */
                rtp_hdr = (rtp_header_t *)SENDBUFFER;
                rtp_hdr->csrc_len = 0;
                rtp_hdr->extension = 0;
                rtp_hdr->padding = 0;
                rtp_hdr->version = 2;
                rtp_hdr->payload_type = H264;
                rtp_hdr->marker = 1; /* 该包为一帧的结尾则置为1, 否则为0. rfc 1889 没有规定该位的用途 */
                rtp_hdr->seq_no = htons(++server->seq_num % UINT16_MAX);
                rtp_hdr->timestamp = htonl(server->ts_current);
                rtp_hdr->ssrc = htonl(server->ssrcNum);

                /*
                     * 2. 设置 rtp 荷载头部
                     */
#if 1
                fu_ind = (fu_indicator_t *)&SENDBUFFER[12];
                fu_ind->f = (nalu_buf[0] & 0x80) >> 7;
                fu_ind->nri = (nalu_buf[0] & 0x60) >> 5;
                fu_ind->type = 28;

                fu_hdr = (fu_header_t *)&SENDBUFFER[13];
                fu_hdr->s = 0;
                fu_hdr->e = 1;
                fu_hdr->r = 0;
                fu_hdr->type = nalu_buf[0] & 0x1f;
#else /* 下面的错误以后找 */
                SENDBUFFER[12] = (nalu_buf[0] & 0x80) >> 7   /* bit0: f */
                                 | (nalu_buf[0] & 0x60) >> 4 /* bit1~2: nri */
                                 | 28 << 3;                  /* bit3~7: type */

                SENDBUFFER[13] = 1 << 1 | (nalu_buf[0] & 0x1f) << 3;
#endif

                /*
                     * 3. 填充rtp荷载
                     */
                memcpy(SENDBUFFER + 14, nalu_buf + RTP_PAYLOAD_MAX_SIZE * fu_seq, last_fu_pack_size); /* 不拷贝nalu头 */

                /*
                     * 4. 发送打包好的rtp包到客户端
                     */
                len_sendbuf = 12 + 2 + last_fu_pack_size;
                send_data_to_client_list(SENDBUFFER, len_sendbuf, server);

            } /* else-if (fu_seq == 0) */
        }     /* end of for (fu_seq = 0; fu_seq < fu_pack_num; fu_seq++) */

    } /* end of else-if (nalu_len <= RTP_PAYLOAD_MAX_SIZE) */

#if 0
    if (nalu_buf) {
        free(nalu_buf);
        nalu_buf = NULL;
    }
#endif

    return 0;
} /* void *h264tortp_send(VENC_STREAM_S *pstream, char *rec_ipaddr) */

static int copy_nal_from_file(FILE *fp, uint8_t *buf, int *len);
static int copy_nal_from_file(FILE *fp, uint8_t *buf, int *len)
{
    char tmpbuf[4];  /* i have forgotten what this var mean */
    char tmpbuf2[1]; /* i have forgotten what this var mean */
    int flag = 0;    /* i have forgotten what this var mean */
    int ret;

#if 0
    ret = fread(tmpbuf, 4, 1, fp);
    if (!ret)
        return 0;
#endif

    *len = 0;

    do
    {
        ret = fread(tmpbuf2, 1, 1, fp);
        if (!ret)
        {
            return -1;
        }
        if (!flag && tmpbuf2[0] != 0x0)
        { //nal的帧头是0 0 1
            buf[*len] = tmpbuf2[0];
            (*len)++;
        }
        else if (!flag && tmpbuf2[0] == 0x0)
        {
            flag = 1;
            tmpbuf[0] = tmpbuf2[0];
        }
        else if (flag)
        {
            switch (flag)
            {
            case 1: //找到一个nal的起始帧
                if (tmpbuf2[0] == 0x0)
                {
                    flag++;
                    tmpbuf[1] = tmpbuf2[0];
                }
                else
                {
                    flag = 0;
                    buf[*len] = tmpbuf[0];
                    (*len)++;
                    buf[*len] = tmpbuf2[0];
                    (*len)++;
                }
                break;
            case 2: //起始帧的下一帧
                if (tmpbuf2[0] == 0x0)
                {
                    flag++;
                    tmpbuf[2] = tmpbuf2[0];
                }
                else if (tmpbuf2[0] == 0x1)
                {
                    flag = 0;
                    return *len;
                }
                else
                {
                    flag = 0;
                    buf[*len] = tmpbuf[0];
                    (*len)++;
                    buf[*len] = tmpbuf[1];
                    (*len)++;
                    buf[*len] = tmpbuf2[0];
                    (*len)++;
                }
                break;
            case 3: //结束帧
                if (tmpbuf2[0] == 0x1)
                {
                    flag = 0;
                    return *len;
                }
                else
                {
                    flag = 0;
                    break;
                }
            }
        }

    } while (1);

    return *len;
} /* static int copy_nal_from_file(FILE *fp, char *buf, int *len) */

int addMissionToRtp(RtpSession *server, char *ipAddr, int port)
{

    server->send_fail_n = 0;
    struct sockaddr_in client;
    client.sin_family = AF_INET;
    client.sin_port = htons(port);
    client.sin_addr.s_addr = inet_addr(ipAddr);
    if ((connect(server->serverSocket, (const struct sockaddr *)&client, sizeof(struct sockaddr_in))) == -1)
    {
        perror("connect");
    }
    return 0;
}
void initRtpServer(RtpSession *server)
{
    struct sockaddr_in server_c;
    const int on = 1;

    server_c.sin_family = AF_INET;
    server_c.sin_port = htons(RTP_PORT);
    server_c.sin_addr.s_addr = htonl(INADDR_ANY);
    server->serverSocket = socket(AF_INET, SOCK_DGRAM, 0);

    /*
     * 设置广播属性
     */
    if (setsockopt(server->serverSocket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
    {
        fprintf(stderr, "initSvr: Socket options set error.\n");
        //   exit(errno);
    }
}

#include "logProc.h"
#include "mongoose.h"
#include "h264_sps.h"
#include "H264.h"
void *rtpSender(void *arg)
{
    pthread_detach(pthread_self());
    RtpSession *server = (RtpSession *)arg;
    FILE *fp;
    int len;
    int ret;

    fp = fopen(server->mediaName, "r");
    if (!fp)
    {
        perror("fopen");
        return 0;
    }

    while (copy_nal_from_file(fp, nal_buf, &len) != -1)
    {
        if (server->blStop)
            break;
        while (server->blPause)
        {
            sleep(1);
            if (server->blStop)
                break;
        }

        ret = h264nal2rtp_send(25, nal_buf, len, server);
        usleep(40000); //1秒25帧，40ms一帧
        if (ret != -1)
            usleep(1000 * 20);
        // 帧缓存已满一帧
    }

    fclose(fp);

    return 0;
}
void startRtpServer(RtpSession *server)
{
    pthread_t t;

    server->blStop = 0;
    pthread_create(&t, NULL, rtpSender, server);
}
void stopRtpServer(RtpSession *server)
{
    server->blStop = 1;
}
void pauseRtpServer(RtpSession *server)
{
    server->blPause = 1;
}

/*
int main(int argc, char **argv)
{


    if (argc < 3) {
        fprintf(stderr, "usage: %s <inputfile> <dstip> [dst_port]\n", argv[0]);
        return -1;
    }
    int port=0;
    if(argc>3)
    {
        port=atoi(argv[3]);
    }
    addMission(argv[1],argv[2],port);

    return 0;
}
*/
